package Lock;

import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.concurrent.locks.AbstractOwnableSynchronizer;


public class AQS extends AbstractOwnableSynchronizer {

    static final class Node {
        //标记，指示一个节点正在共享模式下等待
        static final Node SHARED = new Node();
        //标记，指示节点正在独占模式下等待
        static final Node EXCLUSIVE = null;
        //waitStatus值表示线程已取消
        static final int CANCELLED =  1;
        //waitStatus的值表示后继线程需要被释放
        static final int SIGNAL    = -1;
        //waitStatus值，表示线程正在等待条件
        static final int CONDITION = -2;
        //waitStatus值，指示下一个被获取的应该无条件传播
        static final int PROPAGATE = -3;
        //状态字段，只接受值:
        // SIGNAL:
        //          该节点的继承者是(或即将是)阻塞(通过park)，所以当前节点必须当它释放或取消。
        //          为了避免竞争，获取方法必须首先表明他们需要信号，然后重试原子获取，然后，对失败，阻止。
        //CANCELLED:
        //          该节点由于超时或中断而被取消。节点永远不会离开这个状态。特别是,被取消节点的线程不再阻塞。
        //CONDITION:
        //          该节点目前在条件队列中。它不会被用作同步队列节点直到转移，此时状态将被设置为0。
        //          (这里使用这个值有与the的其他用法无关字段，但简化了机制。)
        //PROPAGATE:
        //          一个releasshared应该传播给other节点。这被设置(仅用于头节点)doreleasshared确保传播
        //          继续，即使其他操作已经因为干预。0:以上都不是数值按数字排列，以简化使用。非负值表示节点不需要负
        //信号。所以，大多数代码不需要检查特定的
        //值，只是符号。
        //对于正常的同步节点，该字段初始化为0
        // CONDITION条件节点。它是使用CAS修改的
        //(或者在可能的情况下，无条件的volatile写操作)。
        volatile int waitStatus;

        volatile Node prev;

        volatile Node next;

        volatile Thread thread;

        Node nextWaiter;

        final boolean isShared(){
            return nextWaiter == SHARED;
        }


        final Node predecessor() throws NullPointerException {
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        }

        Node() { }

        Node(Thread thread, Node mode) {
            this.nextWaiter = mode;
            this.thread = thread;
        }

        Node(Thread thread, int waitStatus) {
            this.waitStatus = waitStatus;
            this.thread = thread;
        }
    }

    private transient volatile Node head;

    private transient volatile Node tail;

    private volatile int state;

    protected final int getState() {
        return state;
    }

    protected final void setState(int newState) {
        state = newState;
    }

    protected final boolean compareAndSetState(int expect, int update) {
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }

    private final boolean compareAndSetHead(Node update) {
        return unsafe.compareAndSwapObject(this, headOffset, null, update);
    }

    final boolean compareAndSetTail(Node expect, Node update) {
        return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
    }
    public Node getHead() {
        return head;
    }

    public Node getTail() {
        return tail;
    }

    public void setHead(Node head) {
        this.head = head;
    }

    public void setTail(Node tail) {
        this.tail = tail;
    }
//   -----------------------
    private static final Unsafe unsafe;
    private static final long stateOffset;
    private static final long headOffset;
    private static final long tailOffset;
    private static final long waitStatusOffset;
    private static final long nextOffset;

    static {
        try {
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            unsafe = (Unsafe) field.get(null);

            stateOffset = unsafe.objectFieldOffset
                    (AQS.class.getDeclaredField("state"));
            headOffset = unsafe.objectFieldOffset
                    (AQS.class.getDeclaredField("head"));
            tailOffset = unsafe.objectFieldOffset
                    (AQS.class.getDeclaredField("tail"));
            waitStatusOffset = unsafe.objectFieldOffset
                    (Node.class.getDeclaredField("waitStatus"));
            nextOffset = unsafe.objectFieldOffset
                    (Node.class.getDeclaredField("next"));
        } catch (Exception ex) { throw new Error(ex); }
    }
}
